﻿using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
using Aop.Api;
using Aop.Api.Request;

using LoginSdk.Model;
using LoginSdk.Utils;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.IdentityModel.Tokens;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;
using Microsoft.Extensions.Configuration;
using WqLunTan.DBContext;
using WqLunTan.Models.DataBase;
using System.Security.Cryptography;
using WqLunTan.Filters;

namespace WqLunTan.Controllers
{
    /// <summary>
    /// 用户登录控制器
    /// </summary>
    public class LoginApiController : BaseController
    {

        /// <summary>
        /// 支付宝登录成功回调页面
        /// </summary>
        /// <param name="auth_code"></param>
        /// <param name="app_id"></param>
        /// <param name="scope"></param>
        /// <param name="state">防止 CSRF 攻击的参数</param>
        /// <returns></returns>
        [AllowAnonymous]
        [HttpGet("AliLoginCallback")]
        public IActionResult AliLoginCallback(string auth_code, string app_id, string scope)
        {
            var session = HttpContext.Session;

            // 根据授权api获取用户id
            var alipay = new DefaultAopClient("https://openapi.alipay.com/gateway.do", AliLoginUtils.ApiConfig.appid, AliLoginUtils.ApiConfig.privatKey, "json", "3.0.1", "RSA2", AliLoginUtils.ApiConfig.publickKey, "UTF-8");
            var req = new AlipaySystemOauthTokenRequest();
            req.Code = auth_code;
            req.GrantType = "authorization_code";
            try
            {
                var token = alipay.Execute(req);
                session.SetString("ali_token", JsonConvert.SerializeObject(token));
                // token.UserId 唯一标识
                if (!string.IsNullOrWhiteSpace(token.UserId))
                {
                    // 登录成功
                    session.SetInt32("login_type", (int)SupportOpenIdTypes.AliBaba);
                    var user = DbContext.Users.Where(x => x.OpenIdAli.Equals(token.UserId)).SingleOrDefault();
                    if (user != null)
                    {
                        if (user.Enable)
                        {
                            // 登录成功, 设置token
                            user.LoginTime = DateTimeOffset.UtcNow;
                            DbContext.SaveChanges();
                            session.setValue("LoginUser", user);
                            session.SetString("jwtToken", GetToken(user));
                            return Redirect("/");
                        }
                        else
                        {
                            return JsonMsg("error", "你的账号被禁止登录", 403);
                        }
                    }
                    else
                    {
                        user = new WqUser()
                        {
                            UserName = $"user_{Guid.NewGuid().ToString("N")}",
                            OpenIdAli = token.UserId,
                            CreateTime = DateTimeOffset.UtcNow,
                            LastUpdate = DateTimeOffset.UtcNow,
                            LoginType = SupportOpenIdTypes.AliBaba,
                            Enable = true
                        };
                        var userCount = DbContext.Users.Count();
                        if (userCount == 0)
                        {
                            user.IsAdmin = true;    // 初始化创建的用户为管理员
                        }
                        // 登录成功, 设置token
                        user.NickName = user.UserName.Substring(0, 10);
                        DbContext.Users.Add(user);
                        DbContext.SaveChanges();

                        user.LoginTime = DateTimeOffset.UtcNow;
                        session.setValue("LoginUser", user);
                        session.SetString("jwtToken", GetToken(user));
                        return Redirect("/");
                    }
                }
            }
            catch (Exception ex)
            {
                var err = ex;
                if (ex.InnerException != null)
                {
                    err = ex.InnerException;
                }
                return Json(new { err.Message, err.StackTrace });
            }

            return Redirect("/");
        }

        /// <summary>
        /// 百度登录回调页面
        /// </summary>
        /// <returns></returns>
        [AllowAnonymous]
        [HttpGet("baiduLoginCallback")]
        public IActionResult baiduLoginCallback(string code)
        {
            var session = HttpContext.Session;
            
            var tokenurl = BaiduLoginUtils.GetTokenUrl(Request.GetCurrentRequestPath(), code);
            var tokenstr = HttpUtils.httpGetString(tokenurl);
            if (tokenstr.Contains("access_token"))
            {
                var token = JsonConvert.DeserializeObject<BaiduToken>(tokenstr);
                if (token != null)
                {
                    var json = HttpUtils.httpGetString(BaiduLoginUtils.GetUidApiUrl(token.access_token));
                    session.SetString("baiduloginjson", json);
                    var baiduuser = JsonConvert.DeserializeObject<BaiduLoginResult>(json);
                    if (baiduuser != null && baiduuser.uid > 0)
                    {
                        // 百度登录成功
                        session.SetInt32("login_type", (int)SupportOpenIdTypes.Baidu);
                        var user = DbContext.Users.Where(x => x.OpenIdBaidu.Equals(baiduuser.uid)).SingleOrDefault();
                        if (user != null)
                        {
                            if (user.Enable)
                            {
                                // 登录成功, 设置token
                                user.LoginTime = DateTimeOffset.UtcNow;
                                DbContext.SaveChanges();
                                session.setValue("LoginUser", user);
                                session.SetString("jwtToken", GetToken(user));
                                return Redirect("/");
                            }
                            else
                            {
                                return JsonMsg("error", "你的账号被禁止登录", 403);
                            }
                        }
                        else
                        {
                            user = new WqUser()
                            {
                                UserName = $"user_{Guid.NewGuid().ToString("N")}",
                                OpenIdBaidu = baiduuser.uid,
                                CreateTime = DateTimeOffset.UtcNow,
                                LastUpdate = DateTimeOffset.UtcNow,
                                LoginType = SupportOpenIdTypes.Baidu,
                                Enable = true
                            };
                            var userCount = DbContext.Users.Count();
                            if (userCount == 0)
                            {
                                user.IsAdmin = true;    // 初始化创建的用户为管理员
                            }
                            // 登录成功, 设置token
                            user.NickName = user.UserName.Substring(0, 10);
                            DbContext.Users.Add(user);
                            DbContext.SaveChanges();

                            user.LoginTime = DateTimeOffset.UtcNow;
                            session.setValue("LoginUser", user);
                            session.SetString("jwtToken", GetToken(user));
                            return Redirect("/");
                        }
                    }
                }
            }

            return Redirect("/");
        }

        /// <summary>
        /// QQ登录
        /// </summary>
        /// <returns></returns>
        [AllowAnonymous]
        [HttpGet("qqlogin")]
        public IActionResult qqLoginCode(string code)
        {
            try
            {
                if (!string.IsNullOrWhiteSpace(code))
                {
                    var getTokenApi = QQLoginUtils.GetTokenApiUrl(Request.GetCurrentRequestPath(), code);
                    var tokenString = HttpUtils.httpGetString(getTokenApi);
                    var url = $"/qqlogintoken?{tokenString}";
                    return Redirect(url);
                }
            }
            catch (Exception ex)
            {
                if (ex.InnerException != null)
                {
                    return JsonMsg("error", new { ex.InnerException.Message, ex.InnerException.StackTrace }, 500);
                }
                return JsonMsg("error", new { ex.Message, ex.StackTrace }, 500);
            }

            return Redirect("/"); // 登录失败
        }

        [AllowAnonymous]
        [HttpGet("/qqlogintoken")]
        public IActionResult QQLoginToken(string access_token, string refresh_token, int expires_in)
        {
            try
            {
                var session = HttpContext.Session;
                if (!string.IsNullOrWhiteSpace(access_token))
                {

                    var openIdApiUrl = $"https://graph.qq.com/oauth2.0/me?access_token={access_token}";
                    var openId = HttpUtils.httpGetString(openIdApiUrl).Replace("callback(", "").Replace(");", "").Trim();

                    if (openId.Contains("openid"))
                    {
                        var result = JsonConvert.DeserializeObject<QQLoginResult>(openId);
                        if (result != null && !string.IsNullOrWhiteSpace(result.openid))
                        {
                            session.SetInt32("login_type", (int)SupportOpenIdTypes.QQ);
                            var user = DbContext.Users.Where(x => x.OpenIdQQ.Equals(result.openid)).SingleOrDefault();
                            if (user != null)
                            {
                                if (user.Enable)
                                {
                                    // 登录成功, 设置token
                                    user.LoginTime = DateTimeOffset.UtcNow;
                                    DbContext.SaveChanges();
                                    session.setValue("LoginUser", user);
                                    session.SetString("jwtToken", GetToken(user));
                                    return Redirect("/");
                                }
                                else
                                {
                                    return JsonMsg("error", "你的账号被禁止登录", 403);
                                }
                            }
                            else
                            {
                                user = new WqUser()
                                {
                                    UserName = $"user_{Guid.NewGuid().ToString("N")}",
                                    OpenIdQQ = result.openid,
                                    CreateTime = DateTimeOffset.UtcNow,
                                    LastUpdate = DateTimeOffset.UtcNow,
                                    LoginType = SupportOpenIdTypes.QQ,
                                    Enable = true
                                };
                                var userCount = DbContext.Users.Count();
                                if (userCount == 0)
                                {
                                    user.IsAdmin = true;    // 初始化创建的用户为管理员
                                }
                                // 登录成功, 设置token
                                user.NickName = user.UserName.Substring(0, 10);
                                DbContext.Users.Add(user);
                                DbContext.SaveChanges();

                                user.LoginTime = DateTimeOffset.UtcNow;
                                session.setValue("LoginUser", user);
                                session.SetString("jwtToken", GetToken(user));
                                return Redirect("/");
                            }
                        }
                    }

                }
            }
            catch (Exception ex)
            {
                if (ex.InnerException != null)
                {
                    return JsonMsg("error", new { ex.InnerException.Message, ex.InnerException.StackTrace }, 500);
                }
                return JsonMsg("error", new { ex.Message, ex.StackTrace }, 500);
            }

            return Redirect("/"); // 登录失败
        }

        /// <summary>
        /// 获取 jwt token
        /// </summary>
        /// <param name="username"></param>
        /// <param name="password"></param>
        /// <returns></returns>
        protected string GetToken(WqUser user)
        {
            if (string.IsNullOrWhiteSpace(user.UserName) || string.IsNullOrWhiteSpace(user.NickName))
            {
                return string.Empty;
            }
            var config = HttpContext.RequestServices.GetService<IConfiguration>();
            var secretKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(config.GetValue<string>("jwtConfig:jwtSecret")));
            var claims = new List<Claim>
            {
                new Claim(JwtRegisteredClaimNames.Sid,  user.Id.ToString())
            };

            var token = new JwtSecurityToken(
                issuer: config.GetValue<string>("jwtConfig:issuer"),    // your app
                audience: config.GetValue<string>("jwtConfig:audience"),     // the client of your app 
                claims: claims,
                notBefore: DateTime.Now,
                expires: DateTime.Now.AddDays(28),
                signingCredentials: new SigningCredentials(secretKey, SecurityAlgorithms.HmacSha256)
            );
            string jwtToken = new JwtSecurityTokenHandler().WriteToken(token);
            return jwtToken;
        }

        /// <summary>
        /// 用户名密码登录
        /// </summary>
        /// <param name="wqUser"></param>
        /// <returns></returns>
        [AllowAnonymous]
        [HttpPost("LoginByPassword")]
        public IActionResult LoginByPassword(WqUser wqUser, bool rememberMe = false)
        {
            var user = DbContext.Users.Where(x => x.UserName.Equals(wqUser.UserName)).SingleOrDefault();
            if (user != null)
            {
                var pwd = Convert.ToBase64String(SHA256.Create().ComputeHash(Encoding.UTF8.GetBytes($"{user.Id.ToString()}_{wqUser.PasswordHash}")));
                if (user.PasswordHash.Equals(pwd))
                {
                    if (user.Enable)
                    {
                        // 登录成功, 设置token
                        var session = HttpContext.Session;
                        user.LoginTime = DateTimeOffset.UtcNow;
                        session.setValue("LoginUser", user);
                        if (rememberMe)
                        {
                            session.SetString("jwtToken", GetToken(user));
                        }
                        return JsonOkResult("登录成功");
                    }
                    else
                    {
                        return JsonFailResult("你的账号被禁止登录");
                    }
                }
            }
            return JsonFailResult("登录失败");
        }

        /// <summary>
        /// 用户注销
        /// </summary>
        /// <returns></returns>
        [HttpGet("logout")]
        public IActionResult Logout()
        {
            var session = HttpContext.Session;
            if (session.Keys.Contains("LoginUser"))
            {
                session.Remove("jwtToken");
                session.Remove("LoginUser");
                return JsonMsg("ok", "注销成功");
            }
            return JsonMsg("fail", "注销失败");
        }

        /// <summary>
        /// 用户登录接口
        /// </summary>
        /// <returns></returns>
        [Auth]
        [HttpGet("init/login")]
        public IActionResult InitLogin()
        {
            try
            {
                var list = User.Claims.ToList();
                StringBuilder sb = new StringBuilder();
                foreach (var item in list)
                {
                    sb.Append($"{item.Type}-{item.Value} ,");
                }
#if DEBUG
                return JsonMsg("ok", sb.ToString());
#else
                return JsonMsg("ok", "login");
#endif
            }
            catch (Exception ex)
            {
                return JsonMsg(ex.Message, ex.StackTrace, 500);
            }
        }

    }
}